<?php
namespace app\common\library\pay\package\smpay;

use think\facade\Cache;

/**
 * 跨境支付通道
 * Class SmPay
 * @author ZhangZheng
 * @package app\common\library\pay\package\smpay
 */
abstract class SmPay{
    protected $private_key;
    protected $branchCode;//接入机构编号

    public $error;
    public $code;
    public $msg;
    public $response;
    public $httpCode;

    //子商户注册接口
    abstract public function income(array $sceneConfig, array $templateParams);
    //修改商户信息
    abstract public function modifys(array $sceneConfig, array $templateParams);
    //绑卡申请
    abstract public function bindCardApply(array $sceneConfig, array $templateParams);
    //绑卡确认
    abstract public function bindCardConfirm(array $sceneConfig, array $templateParams);
    //支付
    abstract public function pay(array $sceneConfig, array $templateParams);
    //消费
    abstract public function consume(array $sceneConfig, array $templateParams);
    //代付
    abstract public function repay(array $sceneConfig, array $templateParams);
    //订单查询
    abstract public function orderQuery(array $sceneConfig, array $templateParams);
    /**
     * 返回错误信息
     * @return mixed
     */
    public function getError()
    {
        return $this->error;
    }
    //加密
    public function encrypt($dataString){
        $priPem = chunk_split($this->private_key, 64, "\n");
        $rsa_private_key = "-----BEGIN PRIVATE KEY-----\n" . $priPem . "-----END PRIVATE KEY-----\n";
        $private_key = openssl_pkey_get_private($rsa_private_key);
        if(!$private_key){
            //公钥不可用
            return ['code'=>0,'msg'=>'私钥不可用','data'=>''];
        }
        $crypted = '';
        foreach (str_split($dataString, 117) as $chunk) {
            if(openssl_private_encrypt($chunk, $encryptData, $private_key)){
                $crypted .= $encryptData;
            }else{
                return ['code'=>0,'msg'=>'加密失败,请检查RSA私钥','data'=>''];
            }
        }
        $eb64_cry = base64_encode($crypted);
        return ['code'=>1,'msg'=>'加密成功','data'=>$eb64_cry];
    }
    //判断json字符串格式
    private function is_json($string)
    {
        json_decode($string);
        return (json_last_error() == JSON_ERROR_NONE);
    }
    //解密
    public function decrypt($eb64_cry){
        $privatePem = chunk_split($this->private_key, 64, "\n");
        $privPem = "-----BEGIN PRIVATE KEY-----\n" . $privatePem . "-----END PRIVATE KEY-----\n";
        $private_key = openssl_pkey_get_private($privPem);
        if(!$private_key){
            return ['code'=>0,'msg'=>'私钥不可用','data'=>''];
        }
        $decrypted = '';
        foreach (str_split(base64_decode($eb64_cry), 128) as $chunk) {
            if(openssl_private_decrypt($chunk, $decryptData, $private_key)){
                $decrypted .= $decryptData;
            }else{
                return ['code'=>0,'msg'=>'解密失败,请检查RSA私钥','data'=>''];
            }
        }
        /*if($this->is_json($decrypted)){
            $decrypted = json_decode($decrypted,true);
        }*/
        return ['code'=>1,'msg'=>'解密成功','data'=> $decrypted];
    }
    //数组转换成键值对字符串
    private function array2string($array){
        $string = [];
        if($array && is_array($array)){
            foreach ($array as $key=> $value){
                $string[] = $key.'='.$value;
            }
        }
        return implode('&',$string);
    }

    private function http_post_json($url, $param)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query($param));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_HTTPHEADER, array(
                'Content-Type: application/x-www-form-urlencoded; charset=utf-8'
            )
        );
        $response = curl_exec($ch);
        //检查是否有错误发生
        if(curl_errno($ch)){
            //发生错误
            $res = ['code'=>false,'httpCode'=>500,'msg'=>curl_error($ch),'response'=>[]];
        }else{
            $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
            if($httpCode == 200){
                $res = ['code'=>true,'httpCode'=>$httpCode,'msg'=>'请求成功','response'=>$response];
            }else{
                $res = ['code'=>false,'httpCode'=>$httpCode,'msg'=>'请求异常','response'=>[]];
            }
        }
        curl_close($ch);
        return $res;
    }

    protected function base($url,$data){
        //判断缓存
        $orderIdKey = 'SM'.$data['orderId'];
        if(Cache::has($orderIdKey)){
            $resJson = Cache::get($orderIdKey);
            $res = json_decode($resJson,true);
            $this->code = $res['code'];
            $this->msg = $res['msg'];
            $response = $res['response'];
            $this->response = $this->deResponse($response);
            $this->httpCode = $res['httpCode'];
            return $this;
        }
        $dataStr = json_encode($data);
        $dataStrArr = $this->encrypt($dataStr);
        if($dataStrArr['code'] == 1){
            $dataCrypt = $dataStrArr['data'];
            $dataCrypt = urlencode($dataCrypt);
            $sigData = [
                'branchCode' => $this->branchCode,
                'data'=>$dataCrypt,
                'version' => '1',
            ];
            $sigDataStr = $this->array2string($sigData);
            $sign = md5($sigDataStr);
            $dataReq = [
                'branchCode' => $this->branchCode,
                'version' => '1',
                'data'=>$dataCrypt,
                'sign'=>$sign,
            ];
            $res = $this->http_post_json($url,$dataReq);
            //缓存6个小时
            Cache::set($orderIdKey,json_encode($res),21600);
            $this->code = $res['code'];
            $this->msg = $res['msg'];
            $response = $res['response'];
            $this->response = $this->deResponse($response);
            $this->httpCode = $res['httpCode'];
        }else{
            $this->code = false;
            $this->msg = $dataStrArr['msg'];
            $this->response = [];
            $this->httpCode = 500;
        }
        return $this;
    }
    //返回值解密
    private function deResponse($json){
        if($this->is_json($json)){
            $jsonObj = json_decode($json);
            if($jsonObj->code == 200 && isset($jsonObj->data)){
                $data = urldecode($jsonObj->data);
                $dataArr = $this->decrypt($data);
                if($dataArr['code']){
                    //解密成功
                    $jsonObj->data = $this->is_json($dataArr['data'])?json_decode($dataArr['data']):$dataArr['data'];
                }
                return $jsonObj;
            }
        }
        return $json;
    }
}
